package com.winit.deploy.manager;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.winit.common.base.beans.LoginUser;
import com.winit.common.util.*;
import com.winit.core.server.factory.LinuxJumpServerFactory;
import com.winit.core.task.ChainBaseTask;
import com.winit.core.task.Task;
import com.winit.core.task.TaskContainer;
import com.winit.deploy.bean.*;
import com.winit.deploy.factory.DeployTaskFactory;
import com.winit.deploy.handler.TaskStatusHandler;
import com.winit.deploy.server.*;
import com.winit.deploy.util.DeployFileUtil;
import com.winit.deploy.util.DeployHandel;
import com.winit.deploy.util.DeployUtil;
import com.winit.jumpServer.bean.JumpServerInfo;
import com.winit.jumpServer.manager.PushRecordManager;
import com.winit.jumpServer.task.PushStatusEnum;
import com.winit.jumpServer.util.JumpServerListInfo;
import com.winit.project.core.bean.PackageTypeEnum;
import com.winit.project.core.branch.Project;
import com.winit.project.core.branch.ProjectStatus;
import com.winit.project.core.edition.PackageEdition;
import com.winit.project.core.edition.PackageEditionConfig;
import com.winit.project.core.set.ProjectSetConfig;
import com.winit.project.manager.ProjectManager;
import com.winit.project.util.ProjectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by wangjian on 16/8/16.
 */
@Component
public class DeployManager {

    private static final Logger logger = LoggerFactory.getLogger(DeployManager.class);

    @Autowired
    private ProjectManager projectManager;
    @Autowired
    private PushRecordManager pushRecordManager;

    public DeployEnv getEnvByName(String envName) {
        try {
            return DeployFileUtil.getDeployEnvInfo(envName);
        } catch (Exception e) {
            logger.error(e.toString());
            return null;
        }
    }

    public List<String> getEnvNames() {
        try {
            return DeployFileUtil.getDeployEnvList();
        } catch (Exception e) {
            logger.error(e.toString());
            return null;
        }
    }

    public AreaStatus getAreaStatus(String envName, String areaName) {
        try {
            return DeployFileUtil.getAreaStatus(envName, areaName);
        } catch (Exception e) {
            logger.error(e.toString());
            return null;
        }
    }

    public JSONObject getEnvTasksStatus(String envName) {
        JSONObject jsonObject = new JSONObject();
        DeployEnv deployEnv = this.getEnvByName(envName);
        List<DeployTaskStatus> deployTaskStatusList = new ArrayList<>();
        Map versionsMap = new HashMap();
        if (null == deployEnv) {
            return null;
        }
        for (DeployArea deployArea : deployEnv.getAreas()) {
            for (DeployTask deployTask : deployArea.getTasks()) {
                DeployTaskStatus deployTaskStatus = null;
                try {
                    JSONObject version = getPassProjectAndEdition(deployTask.getName());
                    if (null != version) {
                        versionsMap.put(deployTask.getName(), version);
                    }
                    deployTaskStatus = DeployFileUtil.getAreaTaskStatus(envName, deployArea.getName(), deployTask.getId());

                    deployTaskStatus = dealTaskStatus(version.getString("projectName"), version.getString("editionNum"), new Date(), deployTaskStatus);
                } catch (Exception e) {
                    logger.error(e.toString());
                    deployTaskStatus = null;
                }
                if (deployTaskStatus != null) {
                    deployTaskStatusList.add(deployTaskStatus);
                }
            }
        }
        jsonObject.put("status", deployTaskStatusList);
        jsonObject.put("versionsMap", versionsMap);

        return jsonObject;
    }

    private DeployTaskStatus dealTaskStatus(String projectName, String editionNum
            , Date date, DeployTaskStatus deployTaskStatus) throws ParseException {
        String version = deployTaskStatus.getVersion();
        if (StringUtils.isEmpty(version) || deployTaskStatus == null) {
            return deployTaskStatus;
        }
        String[] versions = version.split("#");
        String oldProject = versions[0];
        String oldEdition = versions[1];
        String oldDate = versions[2];
        //分支和版本与之前相同,返回当前状态
        if ("default".equals(oldEdition) || (oldProject.equals(projectName) && oldEdition.equals(editionNum))) {
            return deployTaskStatus;
        }

        Integer day = StringUtils.isEmpty(ConfigUtil.getValue("deploy_status_save_day")) ?
                2 : Integer.parseInt(ConfigUtil.getValue("deploy_status_save_day"));

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date oldD = format.parse(oldDate);
        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(date);
        rightNow.add(Calendar.DAY_OF_YEAR, -day);
        Date now = rightNow.getTime();
        List<String> status = deployTaskStatus.getStatus();
        if (oldD.before(now)) {
            //分支和版本不一致时,上次发布时间距离现在超过day天,状态恢复成默认
            deployTaskStatus.setStatusMsg(null);
            deployTaskStatus.setStatus(updateTaskStatus(null, status));
        } else {
            deployTaskStatus.setStatusMsg("分支版本被更新");
            deployTaskStatus.setStatus(updateTaskStatus(Task.TaskStatus.STATUS_WARNING.getValue(), status));
        }
        return deployTaskStatus;
    }

    private List<String> updateTaskStatus(String newStatus, List<String> status) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < status.size(); i++) {
            list.add(newStatus);
        }
        return list;
    }

    public boolean saveAreaStatus(String envName, String areaName, AreaStatus areaStatus) {
        try {
            DeployFileUtil.saveAreaStatus(envName, areaName, areaStatus);
            return true;
        } catch (Exception e) {
            logger.error(e.toString());
            return false;
        }
    }

    public boolean saveEnv(String envName, DeployEnv deployEnv) {
        try {
            DeployFileUtil.saveDeployEnvInfo(envName, deployEnv);
            return true;
        } catch (Exception e) {
            logger.error(e.toString());
        }
        return false;
    }

    public boolean saveArea(String envName, DeployArea area) {
        DeployEnv env = getEnvByName(envName);
        if (env == null) {
            logger.error("找不到环境" + envName);
            return false;
        }
        if (env.getAreas() == null) {
            env.setAreas(new ArrayList<DeployArea>());
        }
        boolean added = false;
        for (int i = 0; i < env.getAreas().size(); i++) {
            DeployArea curArea = env.getAreas().get(i);
            if (curArea.getName().equals(area.getName())) {
                env.getAreas().remove(i);
                env.getAreas().add(i, area);
                added = true;
                break;
            }
        }
        if (!added) {
            env.getAreas().add(area);
        }
        return saveEnv(envName, env);
    }

    public boolean removeArea(String envName, String areaName) {
        DeployEnv env = getEnvByName(envName);
        if (env == null) {
            logger.error("找不到环境" + envName);
            return false;
        }
        for (DeployArea area : env.getAreas()) {
            if (areaName.equals(area.getName())) {
                env.getAreas().remove(area);
                break;
            }
        }
        saveEnv(envName, env);
        return true;
    }

    public void doTask(String envName, String areaName, List<JSONObject> appId, String queueName, String btnType, boolean needPrepare, LoginUser userInfo, Boolean isCleanRedis) throws Exception {
        doTask(envName, areaName, appId, queueName, btnType, needPrepare, userInfo, isCleanRedis, true);
    }

    public void doTask(String envName, String areaName, List<JSONObject> appId, String queueName, String btnType, boolean needPrepare, LoginUser userInfo, Boolean isCleanRedis, boolean needFailConfirm) throws Exception {
        DeployEnv deployEnv = DeployFileUtil.getDeployEnvInfo(envName);

        for (DeployArea deployArea : deployEnv.getAreas()) {
            if (!areaName.equals(deployArea.getName())) {
                continue;
            }
            for (DeployTask deployTask : deployArea.getTasks()) {
                for (JSONObject task : appId) {
                    if (task.getString("taskId").equals(deployTask.getId())) {
                        this.createDeployTask(envName, areaName, deployTask, queueName, btnType,
                                deployArea.getUseJumpServer(), deployArea.getJumpServerIp(), deployArea.getDubboList()
                                , needPrepare, task.getString("projectName"), task.getString("editionNum"), userInfo, isCleanRedis, needFailConfirm);
                        break;
                    }
                }
            }
        }
    }

    private void createDeployTask(String envName, String areaName, DeployTask deployTask, String queueName
            , String btnType, boolean isUserJumpServer, String jumpServerIp, List<DubboVerifyInfo> dubboList
            , boolean needPrepare, String projectName, String editionNum, LoginUser userInfo, boolean isCleanRedis, boolean needFailConfirm) throws Exception {
        DeployTaskFactory factory = new DeployTaskFactory();

        //应用id作为任务id
        String taskId = deployTask.getId();
        logger.info("创建任务,deployTask=" + ObjectToString.getString(deployTask));

        WinitJumpServer jumpServer = null;
        if (isUserJumpServer) {
            jumpServer = LinuxJumpServerFactory.getInstance().getJumpServer(jumpServerIp);
            if (jumpServer == null) {
                throw new Exception("创建发布task,获取跳板机对象为空,请联系beetle管理员!");
            }
        }

        ChainBaseTask.TaskHandler handler = DeployHandel.getDeployHandler(envName, areaName, queueName, projectName, editionNum);

        DeployStepEnum step = null;
        try {
            step = Enum.valueOf(DeployStepEnum.class, btnType.toUpperCase());
        } catch (Exception e) {
            logger.error("创建发布task,参数错误.btnType=" + btnType, e);
            throw new Exception("创建发布task,参数错误.btnType=" + btnType);
        }

        ChainBaseTask chainBaseTask = null;
        //区分java工程和php工程
        if ("tomcat".equals(deployTask.getType())) {
            WinitTomcatInfo winitTomcatInfo = getWinitTomcatInfo(envName, areaName, deployTask, "rollback".equals(btnType), projectName, editionNum);
            winitTomcatInfo.setQueueName(queueName);
            WinitTomcatServer winitTomcatServer = new WinitTomcatServer(deployTask.getIp(), ConfigUtil.getValue("ssh_login_user")
                    , deployTask.getPort(), winitTomcatInfo);
            winitTomcatServer.addPrivateKeyPath("/home/" + ConfigUtil.getValue("ssh_login_user") + "/" + ConfigUtil.getValue("ssh_key_file"));
            winitTomcatServer.setDubboList(dubboList);
            winitTomcatServer.setConnectionTimeout(Constants.SSH_CONNECT_TIMEOUT);
            if (isUserJumpServer) {
                jumpServer.jump(winitTomcatServer);
            }
            chainBaseTask = factory.createChainBaseTask(PackageTypeEnum.MAVEN_WAR, step, taskId, winitTomcatServer, isUserJumpServer, jumpServer, winitTomcatInfo, handler, needPrepare, userInfo, needFailConfirm, isCleanRedis);
        } else if ("php".equals(deployTask.getType())) {
            WinitPhpInfo phpInfo = getWinitPhpInfo(envName, areaName, deployTask, "rollback".equals(btnType), projectName, editionNum);
            phpInfo.setQueueName(queueName);
            WinitPhpServer phpServer = new WinitPhpServer(deployTask.getIp(), ConfigUtil.getValue("ssh_login_user")
                    , deployTask.getPort(), phpInfo);
            phpServer.addPrivateKeyPath("/home/" + ConfigUtil.getValue("ssh_login_user") + "/" + ConfigUtil.getValue("ssh_key_file"));
            Integer timeOut = StringUtils.isEmpty(ConfigUtil.getValue("ssh_server_connect_timeout")) ?
                    10000 : Integer.parseInt(ConfigUtil.getValue("ssh_server_connect_timeout"));
            phpServer.setConnectionTimeout(timeOut);
            if (isUserJumpServer) {
                jumpServer.jump(phpServer);
            }
            chainBaseTask = factory.createChainBaseTask(PackageTypeEnum.PHP, step, taskId, phpServer, isUserJumpServer, jumpServer, phpInfo, handler, needPrepare, userInfo, needFailConfirm);
        } else if ("ant_android".equals(deployTask.getType())) {
            WinitAndroidInfo androidInfo = getWinitAndroidInfo(envName, areaName, deployTask, "rollback".equals(btnType), projectName, editionNum);
            androidInfo.setQueueName(queueName);
            WinitAndroidServer androidServer = new WinitAndroidServer(deployTask.getIp(), ConfigUtil.getValue("ssh_login_user")
                    , deployTask.getPort(), androidInfo);
            androidServer.addPrivateKeyPath("/home/" + ConfigUtil.getValue("ssh_login_user") + "/" + ConfigUtil.getValue("ssh_key_file"));
            Integer timeOut = StringUtils.isEmpty(ConfigUtil.getValue("ssh_server_connect_timeout")) ?
                    10000 : Integer.parseInt(ConfigUtil.getValue("ssh_server_connect_timeout"));
            androidServer.setConnectionTimeout(timeOut);
            if (isUserJumpServer) {
                jumpServer.jump(androidServer);
            }
            chainBaseTask = factory.createChainBaseTask(PackageTypeEnum.ANT_ANDROID, step, taskId, androidServer, isUserJumpServer, jumpServer, androidInfo, handler, needPrepare, userInfo, needFailConfirm);
        } else if ("spring_boot_jar".equals(deployTask.getType())) {
            WinitSpringBootInfo info = getSpringBootInfo(envName, areaName, deployTask, "rollback".equals(btnType), projectName, editionNum);
            info.setQueueName(queueName);
            WinitSpringBootServer server = new WinitSpringBootServer(deployTask.getIp(), ConfigUtil.getValue("ssh_login_user")
                    , deployTask.getPort(), info);
            server.addPrivateKeyPath("/home/" + ConfigUtil.getValue("ssh_login_user") + "/" + ConfigUtil.getValue("ssh_key_file"));
            Integer timeOut = StringUtils.isEmpty(ConfigUtil.getValue("ssh_server_connect_timeout")) ?
                    10000 : Integer.parseInt(ConfigUtil.getValue("ssh_server_connect_timeout"));
            server.setConnectionTimeout(timeOut);
            if (isUserJumpServer) {
                jumpServer.jump(server);
            }
            chainBaseTask = factory.createChainBaseTask(PackageTypeEnum.SPRING_BOOT_JAR, step, taskId, server, isUserJumpServer, jumpServer, info, handler, needPrepare, userInfo, needFailConfirm);
        }
        DeployFileUtil.saveTaskInfo(envName, areaName, taskId, projectName, editionNum, btnType);

        TaskStatusHandler taskStatusHandler = TaskStatusHandler.getInstance();
        taskStatusHandler.addArea(envName, areaName, queueName, taskId);

        TaskContainer taskContainer = TaskContainer.getInstance();
        taskContainer.addTask(chainBaseTask);
    }

//    private ChainBaseTask.TaskHandler getHandler(final String envName, final String areaName, final String queueName
//            , final String projectName, final String editionNum) {
//        ChainBaseTask.TaskHandler handler = new ChainBaseTask.TaskHandler() {
//            @Override
//            public void handleTaskNodeStatus(String taskId, List<String> taskNodeStatus) {
//                System.out.println(DateUtil.getCurDateStr(DateUtil.FORMAT_SS) + taskId + ":chainBaseTask sendTaskStatus:");
//                for (String s : taskNodeStatus)
//                    System.out.println(DateUtil.getCurDateStr(DateUtil.FORMAT_SS) + taskId + ":执行状态=======" + s);
//
//                Map head = new HashMap();
//                head.put("queueName", queueName);
//                head.put("envName", envName);
//                head.put("areaName", areaName);
//                head.put("type", "areaTaskStatus");
//
//                JSONObject object = new JSONObject();
//                object.put("id", taskId);
//                object.put("status", taskNodeStatus);
//
//                Message<JSONObject> message = new Message<>(head, object);
//                MessageExchange messageExchange = SpringContextHolder.getBean(MessageExchange.class);
//                messageExchange.sendMessage(queueName, message);
//
//                DeployTaskStatus taskStatus = DeployFileUtil.getAreaTaskStatus(envName, areaName, taskId);
//                taskStatus.setId(taskId);
//                taskStatus.setStatus(taskNodeStatus);
//                DeployFileUtil.saveTaskStatus(envName, areaName, taskId, taskStatus, projectName, editionNum);
//
//            }
//
//            @Override
//            public void handleChainTaskStatus(String taskId, String taskStatus) {
//                if (!Task.TaskStatus.STATUS_RUNNING.getValue().equals(taskStatus)
//                        && !Task.TaskStatus.STATUS_PAUSE.getValue().equals(taskStatus)
//                        && !Task.TaskStatus.STATUS_CONTINUE.getValue().equals(taskStatus)) {
//                    TaskStatusHandler taskStatusHandler = TaskStatusHandler.getInstance();
//                    taskStatusHandler.handleAreaTaskStatus(envName, areaName, taskId, queueName);
//                }
//
//                if (Task.TaskStatus.STATUS_PAUSE.getValue().equals(taskStatus)) {
//                    Map head = new HashMap();
//                    head.put("queueName", queueName);
//                    head.put("envName", envName);
//                    head.put("areaName", areaName);
//                    head.put("type", "areaTaskStatus");
//
//                    JSONObject object = new JSONObject();
//                    object.put("id", taskId);
//                    object.put("confirm", "true");
//                    Message<JSONObject> me = new Message<>(head, object);
//                    MessageExchange messageExchange = SpringContextHolder.getBean(MessageExchange.class);
//                    messageExchange.sendMessage(queueName, me);
//                }
//
//                if (Task.TaskStatus.STATUS_CONTINUE.getValue().equals(taskStatus)
//                        || Task.TaskStatus.STATUS_STOP.getValue().equals(taskStatus)) {
//                    Map head = new HashMap();
//                    head.put("queueName", queueName);
//                    head.put("envName", envName);
//                    head.put("areaName", areaName);
//                    head.put("type", "areaTaskStatus");
//
//                    JSONObject object = new JSONObject();
//                    object.put("id", taskId);
//                    object.put("confirm", "false");
//                    Message<JSONObject> me = new Message<>(head, object);
//                    MessageExchange messageExchange = SpringContextHolder.getBean(MessageExchange.class);
//                    messageExchange.sendMessage(queueName, me);
//                }
//
//                System.out.println(DateUtil.getCurDateStr(DateUtil.FORMAT_SS) + taskId + ":chainBaseTask taskStatus:" + taskStatus);
//            }
//
//            @Override
//            public void handleChainTaskMessage(String taskId, String message) {
//                System.out.println(DateUtil.getCurDateStr(DateUtil.FORMAT_SS) + taskId + ":chainBaseTask message:" + message);
//
//                Map head = new HashMap();
//                head.put("queueName", queueName);
//                head.put("envName", envName);
//                head.put("areaName", areaName);
//                head.put("type", "areaTaskStatus");
//
//                JSONObject object = new JSONObject();
//                object.put("id", taskId);
//                object.put("statusMsg", message);
//
//                Message<JSONObject> me = new Message<>(head, object);
//                MessageExchange messageExchange = SpringContextHolder.getBean(MessageExchange.class);
//                messageExchange.sendMessage(queueName, me);
//
//                DeployTaskStatus taskStatus = DeployFileUtil.getAreaTaskStatus(envName, areaName, taskId);
//                taskStatus.setId(taskId);
//                taskStatus.setStatusMsg(message);
//                DeployFileUtil.saveTaskStatus(envName, areaName, taskId, taskStatus, projectName, editionNum);
//            }
//        };
//        return handler;
//    }

    private WinitSpringBootInfo getSpringBootInfo(String envName, String areaName, DeployTask deployTask
            , boolean isRollBack, String projectName, String editionNum) throws Exception {
        if (StringUtils.isEmpty(projectName) || !projectManager.isProjectExist(projectName)) {
            logger.error("创建非停机发版任务,工程不存在!name=" + projectName);
            throw new Exception("创建非停机发版任务,工程不存在!name=" + projectName);
        }

        Project project = new Project(projectName, true);
        ProjectSetConfig setConfig = project.getProjectSetConfig();

        String serverPath = deployTask.getServerPath();
        String warName = setConfig.getWarName();

        String backUpPath = null;
        if (isRollBack) {
            backUpPath = deployTask.getBackUpPath();
        } else {
            String bakName = DeployUtil.getBakFileName(warName);
//            backUpPath = Constants.RELEASE_BAK_DIR+"/" + bakName;
            backUpPath = "/usr/local/spring-boot-bak/" + bakName;
        }
        if (StringUtils.isEmpty(backUpPath)) {
            logger.error("创建非停机发版任务,回滚工程,备份路径为空");
            throw new Exception("创建非停机发版任务,回滚工程,备份路径为空");
        }

        String serverIp = deployTask.getIp();
        String sshPort = String.valueOf(deployTask.getPort());

        //校验配置文件,生成发布war包
        if (StringUtils.isEmpty(editionNum)) {
            throw new Exception("该工程没有测试通过版本,请联系测试人员!工程名:" + projectName);
        }
        if (!projectManager.isEditionExist(projectName, editionNum)) {
            throw new Exception("要发布的版本不存在,请联系测试人员或beetle管理员!工程名:" + projectName + ",版本号:" + editionNum);
        }

        String jarPath = ConfigUtil.getValue("rootPath") + "Beetle/release/temp/" + envName + "/" + areaName + "/"
                + deployTask.getId() + "/" + warName + ".tgz";
//        String jarTempDir = Constants.RELEASE_PREPARE_TEMP_DIR;
        String jarTempDir = "/usr/local/beetle";
        String userName = ConfigUtil.getValue("ssh_login_user");
        String keyFilePath = "/home/" + ConfigUtil.getValue("ssh_login_user") + "/" + ConfigUtil.getValue("ssh_key_file");
        String configPath = deployTask.getConfigPath();

        WinitSpringBootInfo info = new WinitSpringBootInfo(serverPath, backUpPath,
                warName, serverIp, sshPort, jarPath, jarTempDir, userName, keyFilePath
                , projectName, editionNum, configPath, envName, areaName);
//        info.setBackUpDir(Constants.RELEASE_BAK_DIR);
        info.setBackUpDir("/usr/local/spring-boot-bak");
        return info;
    }

    private WinitPhpInfo getWinitPhpInfo(String envName, String areaName, DeployTask deployTask
            , boolean isRollBack, String projectName, String editionNum) throws Exception {
        if (StringUtils.isEmpty(projectName) || !projectManager.isProjectExist(projectName)) {
            logger.error("创建非停机发版任务,工程不存在!name=" + projectName);
            throw new Exception("创建非停机发版任务,工程不存在!name=" + projectName);
        }

        WinitPhpInfo phpInfo = new WinitPhpInfo();

        Project project = new Project(projectName, true);
        ProjectSetConfig setConfig = project.getProjectSetConfig();

        phpInfo.setServerIp(deployTask.getIp());
        phpInfo.setSshPort(String.valueOf(deployTask.getPort()));
        phpInfo.setUserName(ConfigUtil.getValue("ssh_login_user"));
        phpInfo.setKeyFilePath("/home/" + ConfigUtil.getValue("ssh_login_user") + "/" + ConfigUtil.getValue("ssh_key_file"));
        phpInfo.setProjectName(projectName);
        phpInfo.setEditionNum(editionNum);
        phpInfo.setConfigPath(deployTask.getConfigPath());
        phpInfo.setEnvName(envName);
        phpInfo.setAreaName(areaName);
        phpInfo.setDstUser(deployTask.getDstUser());

        String serverPath = deployTask.getServerPath();
        String[] dir = serverPath.split("/");

        phpInfo.setProjectDirPath(serverPath.replace("/" + dir[dir.length - 1], ""));
        phpInfo.setProjectDirName(dir[dir.length - 1]);

        String packageName = setConfig.getPackageName();

        String backUpPath = null;
        if (isRollBack) {
            backUpPath = deployTask.getBackUpPath();
        } else {
            String bakName = DeployUtil.getBakFileName(packageName);
//            backUpPath = Constants.RELEASE_BAK_DIR + "/" + bakName;
//            phpInfo.setBackUpDir(Constants.RELEASE_BAK_DIR);
            backUpPath = phpInfo.getProjectDirPath() + "/phpBak/" + bakName;
            phpInfo.setBackUpDir(phpInfo.getProjectDirPath() + "/phpBak");
        }
        if (StringUtils.isEmpty(backUpPath)) {
            logger.error("创建非停机发版任务,回滚工程,备份路径为空");
            throw new Exception("创建非停机发版任务,回滚工程,备份路径为空");
        }
        phpInfo.setBackUpPath(backUpPath);
        phpInfo.setZipPath(ConfigUtil.getValue("rootPath") + "Beetle/release/temp/" + envName + "/" + areaName + "/"
                + deployTask.getId() + "/" + packageName + ".zip");
//        phpInfo.setZipTempDir(Constants.RELEASE_PREPARE_TEMP_DIR);
        phpInfo.setZipTempDir(phpInfo.getProjectDirPath() + "/beetle");
        phpInfo.setPackageName(packageName);
        return phpInfo;
    }

    private WinitAndroidInfo getWinitAndroidInfo(String envName, String areaName, DeployTask deployTask
            , boolean isRollBack, String projectName, String editionNum) throws Exception {
        if (StringUtils.isEmpty(projectName) || !projectManager.isProjectExist(projectName)) {
            logger.error("创建非停机发版任务,工程不存在!name=" + projectName);
            throw new Exception("创建非停机发版任务,工程不存在!name=" + projectName);
        }

        WinitAndroidInfo androidInfo = new WinitAndroidInfo();

        Project project = new Project(projectName, true);
        ProjectSetConfig setConfig = project.getProjectSetConfig();

        androidInfo.setServerIp(deployTask.getIp());
        androidInfo.setSshPort(String.valueOf(deployTask.getPort()));
        androidInfo.setUserName(ConfigUtil.getValue("ssh_login_user"));
        androidInfo.setKeyFilePath("/home/" + ConfigUtil.getValue("ssh_login_user") + "/" + ConfigUtil.getValue("ssh_key_file"));
        androidInfo.setProjectName(projectName);
        androidInfo.setEditionNum(editionNum);
//        phpInfo.setConfigPath(deployTask.getConfigPath());
        androidInfo.setEnvName(envName);
        androidInfo.setAreaName(areaName);
        androidInfo.setDstUser(deployTask.getDstUser());

        String serverPath = deployTask.getServerPath();
        String[] dir = serverPath.split("/");

        androidInfo.setProjectDirPath(serverPath.replace("/" + dir[dir.length - 1], ""));
        androidInfo.setProjectDirName(dir[dir.length - 1]);

        String packageName = setConfig.getPackageName();

        String backUpPath = null;
        if (isRollBack) {
            backUpPath = deployTask.getBackUpPath();
        } else {
            String bakName = DeployUtil.getBakFileName(packageName);
//            String bakdir = Constants.RELEASE_BAK_DIR;
            String bakdir = "/usr/local/phpBak";
            backUpPath = bakdir + "/" + bakName;
            androidInfo.setBackUpDir(bakdir);
        }
        if (StringUtils.isEmpty(backUpPath)) {
            logger.error("创建非停机发版任务,回滚工程,备份路径为空");
            throw new Exception("创建非停机发版任务,回滚工程,备份路径为空");
        }
        androidInfo.setBackUpPath(backUpPath);
        androidInfo.setZipPath(ConfigUtil.getValue("rootPath") + "Beetle/release/temp/" + envName + "/" + areaName + "/"
                + deployTask.getId() + "/" + packageName + ".zip");
//        androidInfo.setZipTempDir(Constants.RELEASE_PREPARE_TEMP_DIR);
        androidInfo.setZipTempDir(androidInfo.getProjectDirPath() + "/beetle");
        androidInfo.setPackageName(packageName);
        return androidInfo;
    }

    private WinitTomcatInfo getWinitTomcatInfo(String envName, String areaName, DeployTask deployTask
            , boolean isRollBack, String projectName, String editionNum) throws Exception {
        if (StringUtils.isEmpty(projectName) || !projectManager.isProjectExist(projectName)) {
            logger.error("创建非停机发版任务,工程不存在!name=" + projectName);
            throw new Exception("创建非停机发版任务,工程不存在!name=" + projectName);
        }

        Project project = new Project(projectName, true);
        ProjectSetConfig setConfig = project.getProjectSetConfig();

        String serverPath = deployTask.getServerPath();
        String logPath = deployTask.getServerPath() + "/logs/catalina.out";
        String projectDir = deployTask.getServerPath() + "/webapps";
        String httpPort = String.valueOf(deployTask.getHttpPort());

        String warName = setConfig.getWarName();

        String backUpPath = null;
        if (isRollBack) {
            backUpPath = deployTask.getBackUpPath();
        } else {
            String bakName = DeployUtil.getBakFileName(warName);
//            backUpPath = Constants.RELEASE_BAK_DIR + "/" + bakName;
            backUpPath = deployTask.getServerPath() + "/webapps/" + bakName;
        }
        if (StringUtils.isEmpty(backUpPath)) {
            logger.error("创建非停机发版任务,回滚工程,备份路径为空");
            throw new Exception("创建非停机发版任务,回滚工程,备份路径为空");
        }

        String system = StringUtils.isEmpty(ConfigUtil.getValue("deploy_system")) ? "centos" : ConfigUtil.getValue("deploy_system");
        String javaHome = deployTask.getJavaHome();
        String serverIp = deployTask.getIp();
        String sshPort = String.valueOf(deployTask.getPort());

        //校验配置文件,生成发布war包
        if (StringUtils.isEmpty(editionNum)) {
            throw new Exception("该工程没有测试通过版本,请联系测试人员!工程名:" + projectName);
        }
        if (!projectManager.isEditionExist(projectName, editionNum)) {
            throw new Exception("要发布的版本不存在,请联系测试人员或beetle管理员!工程名:" + projectName + ",版本号:" + editionNum);
        }

        String warPath = ConfigUtil.getValue("rootPath") + "Beetle/release/temp/" + envName + "/" + areaName + "/"
                + deployTask.getId() + "/" + warName + ".war";
//        String warTempPath = Constants.RELEASE_PREPARE_TEMP_DIR;
        String warTempPath = deployTask.getServerPath() + "/beetle";
        String userName = ConfigUtil.getValue("ssh_login_user");
        String keyFilePath = "/home/" + ConfigUtil.getValue("ssh_login_user") + "/" + ConfigUtil.getValue("ssh_key_file");
        String configPath = deployTask.getConfigPath();

        WinitTomcatInfo winitTomcatInfo = new WinitTomcatInfo(serverPath, logPath, projectDir, backUpPath, httpPort, system, javaHome,
                warName, serverIp, sshPort, warPath, warTempPath, userName, keyFilePath
                , projectName, editionNum, configPath, envName, areaName);
//        winitTomcatInfo.setBackUpDir(Constants.RELEASE_BAK_DIR);
        winitTomcatInfo.setBackUpDir(deployTask.getServerPath() + "/webapps");
        return winitTomcatInfo;
    }

    //任务出现异常时,提醒回调
    public boolean confirmCallBack(String taskId, String type) {
        TaskContainer taskContainer = TaskContainer.getInstance();
        ChainBaseTask chainBaseTask = (ChainBaseTask) taskContainer.getTask(taskId);
        if (chainBaseTask == null) {
            logger.info("弹窗回调,chainBaseTask == null");
            return true;
        }
        if ("0".equals(type)) {
            chainBaseTask.continueTask();
        } else if ("1".equals(type)) {
            chainBaseTask.stopTask();
        }
        return true;
    }

    //准备阶段进行校验 java工程
    public boolean deployPrepare(WinitInfo info, String taskId) throws Exception {
        String projectName = info.getProjectName();
        String editionNum = info.getEditionNum();
        //检出配置文件
        Project project = new Project(projectName, true);
        String configProjectName = project.getProjectSetConfig().getConfigProjectName();

        StringBuffer configSvnURL = new StringBuffer();
        configSvnURL.append(ConfigUtil.getValue("env_config_check_svn_path")).append(info.getConfigPath()).append("/").append(configProjectName);

        String toPath = ProjectUtil.getProjectFilePath(projectName) + editionNum + "/release";
        ProjectUtil.checkOutConfigFile(configSvnURL.toString(), toPath, taskId);

        //校验配置文件是否正确
        String baseConfigPath = project.getProjectCode().getCodePath();
        ProjectSetConfig setConfig = project.getProjectSetConfig();
        String subModule = setConfig.getSubModule();

        if (!StringUtils.isEmpty(subModule)) {
            baseConfigPath = baseConfigPath + "/" + subModule;
        }
        try {
            ProjectUtil.checkConfigFile(toPath + "/" + taskId, baseConfigPath);
        } catch (Exception e) {
            logger.error("com.winit.deploy.manager.DeployManager.deployPrepare 校验配置文件异常。", e);
            if (!info.isVmEnv()) {
                throw e;
            }
        }
        return true;
    }

    /**
     * 测试通过或测试不通过时,修改记录
     *
     * @param projectName
     * @param editionNum
     * @param status
     * @return
     * @throws Exception
     */
    public boolean updateProjectTestPassEdition(String projectName, String editionNum, String status, LoginUser userInfo) throws Exception {
        boolean flag = false;
        Project project = new Project(projectName, true);
        ProjectStatus projectStatus = project.getProjectStatus();
        if (Constants.PROJECT_EDITION_TEST_STATUS_NOT_PASS.equals(status)) {
            LogUtil.operateLog(userInfo, projectName, editionNum, "", LogUtil.OperateType.TEST_NOT_PASS);
            flag = DeployUtil.delProjectVersion(projectName, editionNum, DeployEnum.TESTPASS);
            //如果当前版本为提交测试版本,清空工程提交测试版本信息

//            String toTestEdition = projectStatus.getQaTestEdition();
//            if(!StringUtils.isEmpty(toTestEdition) && toTestEdition.equals(editionNum)){
//                projectStatus.setQaTestEdition("");
//            }
            projectStatus.setLastPass(false);
            projectStatus.saveToFile();
            //保存版本测试不通过状态
            PackageEdition edition = new PackageEdition(projectName, editionNum, true);
            PackageEditionConfig config = edition.getPackageEditionConfig();
            config.setNotTestPass(true);
            config.saveToFile();
        } else if (Constants.PROJECT_EDITION_TEST_STATUS_PASS.equals(status)) {//标记为通过版本
            LogUtil.operateLog(userInfo, projectName, editionNum, "", LogUtil.OperateType.TEST_PASS);
            //测试通过,将版本拷贝至nas

            projectStatus.setLastPass(true);
            projectStatus.saveToFile();

            PackageEdition edition = new PackageEdition(projectName, editionNum, true);
            ProjectUtil.scpMvnEditionToRelease(projectName, editionNum);
            //保存版本测试不通过状态
            PackageEditionConfig config = edition.getPackageEditionConfig();
            config.setNotTestPass(false);
            config.saveToFile();
            //测试通过,推送版本包至跳板机
            if (JumpServerListInfo.jumpServerInfo.size() > 0) {
                pushRecordManager.createPush(projectName, editionNum, true, userInfo);
            } else {
                project.updatePushStatus(PushStatusEnum.NEVER_PUSH, "", editionNum);
            }
            flag = true;
        }
        return flag;
    }

    /**
     * 获取测试通过版本号
     *
     * @param projectName
     * @return
     * @throws Exception
     */
    public String getPassEditionNum(String projectName) throws Exception {
        JSONObject object = getPassProjectAndEdition(projectName);
        return object.getString("editionNum");
    }

    /**
     * 获取线上/staging工程名及版本号
     *
     * @param trunkName
     * @param type
     * @return
     */
    public String getOnlineOrStagingVersion(String trunkName, DeployEnum deployEnum, String type) {
        return DeployUtil.getProjectVersion(trunkName, deployEnum, type);
    }

    public JSONObject getPassProjectAndEdition(String projectName) throws Exception {
        projectName = ProjectUtil.getTrunkProjectName(projectName);
        Project project = new Project(projectName, true);
        if (!project.isProjectExist()) {
            logger.error("查询工程测试通过版本,工程不存在.projectName=" + projectName);
            throw new Exception("查询工程测试通过版本,工程不存在.projectName=" + projectName);
        }
        JSONObject data = new JSONObject();
        String version = DeployUtil.getProjectVersion(projectName, DeployEnum.TESTPASS, "");
        if (StringUtils.isEmpty(version)) {
            data.put("projectName", "");
            data.put("editionNum", "");
            return data;
        }

        String[] ver = version.split("#");
        data.put("projectName", ver[0]);
        data.put("editionNum", ver[1]);
        return data;
    }

    /**
     * 当who测试通过时，自动发布who到线上环境，并发送邮件通知运维
     */
    public void autoDeployWho(LoginUser userInfo, String jumpServerIp) {
        autoDeployWho(userInfo, jumpServerIp, null, null);
    }

    public void autoDeployWho(LoginUser userInfo, String jumpServerIp, String projectName, String editionNum) {
        if (null == userInfo) {
            logger.error("com.winit.deploy.manager.DeployManager.autoDeployWho 用户信息为空");
            return;
        }

        try {
            if (StringUtils.isEmpty(projectName) && StringUtils.isEmpty(editionNum)) {
                //获取测试通过版本
                JSONObject jsonObject = getPassProjectAndEdition("who");
                projectName = jsonObject.getString("projectName");
                editionNum = jsonObject.getString("editionNum");
            }

            Assert.notNull(projectName, "autoDeployWho projectName为空");
            Assert.notNull(editionNum, "autoDeployWho editionNum为空");
            Assert.isTrue(!"who".equalsIgnoreCase(projectName), "autoDeployWho 不能发布主干工程.");
            Assert.isTrue(projectManager.isEditionExist(projectName, editionNum), "autoDeployWho 工程版本不存在.projectName=" + projectName + ".editionNum=" + editionNum);

            logger.info("com.winit.deploy.manager.DeployManager.autoDeployWho userInfo=" + ObjectToString.getString(userInfo) + ".projectName=" + projectName + ".editionNum=" + editionNum);

            String envs = ConfigUtil.getValue("auto_deploy_who_env");
            if (StringUtils.isEmpty(envs)) {
                logger.info("com.winit.deploy.manager.DeployManager.autoDeployWho env is null");
                return;
            }

            for (String env : envs.split(",")) {
                //获取env下所有区域的who配置
                DeployEnv deployEnv = getEnvByName(env);
                if (null == deployEnv) {
                    logger.error("com.winit.deploy.manager.DeployManager.autoDeployWho " + env + " 环境信息为空");
                    continue;
                }
                for (DeployArea area : deployEnv.getAreas()) {
                    //不考虑不使用跳板机的情况
                    if (!area.getUseJumpServer()) {
                        continue;
                    }
                    if (!jumpServerIp.equals(area.getJumpServerIp()) && !"all".equals(jumpServerIp)) {
                        continue;
                    }
                    String queueName = "release-" + env + "-" + area.getName() + "-" + "status";
                    List<JSONObject> appId = new ArrayList<>();
                    for (DeployTask task : area.getTasks()) {
                        if ("who".equals(task.getName())) {
                            JSONObject object = new JSONObject();
                            object.put("taskId", task.getId());
                            object.put("projectName", projectName);
                            object.put("editionNum", editionNum);
                            appId.add(object);
                        }
                    }
                    if (appId.size() == 0) {
                        continue;
                    }
                    doTask(env, area.getName(), appId, queueName, "all", true, userInfo, false, false);
                }
            }
        } catch (Exception e) {
            logger.error("com.winit.deploy.manager.DeployManager.autoDeployWho 异常", e);
            //异常发送邮件
            String subject = "【异常】who自动发布异常通知";
            String body = "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><title>Title</title></head><body>" +
                    "<span style='color:red;'>跳板机：" + jumpServerIp + "推送完成后发布who异常</span><br>工程：" + projectName +
                    "<br>版本：" + editionNum + "<br>异常信息：<span style='color:red;'>" + e + "</span></body></html>";
            MailUtil.sendMail(ConfigUtil.getValue("auto_deploy_who_notify_user"), subject, body);
        }
    }
}
